summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
m---------externals/SDL0
m---------externals/nx_tzdb/tzdb_to_nx0
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt6
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt34
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt23
-rw-r--r--src/android/app/src/main/jni/native.cpp91
-rw-r--r--src/core/hid/emulated_controller.cpp19
-rw-r--r--src/input_common/drivers/sdl_driver.cpp28
-rw-r--r--src/input_common/helpers/joycon_driver.cpp42
-rw-r--r--src/input_common/helpers/joycon_driver.h1
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.cpp8
13 files changed, 138 insertions, 120 deletions
diff --git a/externals/SDL b/externals/SDL
-Subproject c27f3ead7c37bcbef608f385baa9fce7232efc6
+Subproject 491fba1d06a4810645092b2559b9cc94abeb23b
diff --git a/externals/nx_tzdb/tzdb_to_nx b/externals/nx_tzdb/tzdb_to_nx
-Subproject 8c272f21d19c6e821345fd055f41b9640f9189d
+Subproject 212afa2394a74226dcf1b7996a570aae17debb6
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt
index dd6c895fd..f54dccc69 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt
@@ -29,7 +29,6 @@ import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
-import org.yuzu.yuzu_emu.utils.FileUtil
class SearchFragment : Fragment() {
private var _binding: FragmentSearchBinding? = null
@@ -128,10 +127,7 @@ class SearchFragment : Fragment() {
R.id.chip_homebrew -> baseList.filter { it.isHomebrew }
- R.id.chip_retail -> baseList.filter {
- FileUtil.hasExtension(it.path, "xci") ||
- FileUtil.hasExtension(it.path, "nsp")
- }
+ R.id.chip_retail -> baseList.filter { !it.isHomebrew }
else -> baseList
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
index 6a048e39f..6527c64ab 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
@@ -43,7 +43,7 @@ class Game(
companion object {
val extensions: Set<String> = HashSet(
- listOf(".xci", ".nsp", ".nca", ".nro")
+ listOf("xci", "nsp", "nca", "nro")
)
}
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
index 3086cfad3..f7d7aed1e 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
@@ -296,7 +296,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
return@registerForActivityResult
}
- if (!FileUtil.hasExtension(result, "keys")) {
+ if (FileUtil.getExtension(result) != "keys") {
MessageDialogFragment.newInstance(
R.string.reading_keys_failure,
R.string.install_prod_keys_failure_extension_description
@@ -393,7 +393,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
return@registerForActivityResult
}
- if (!FileUtil.hasExtension(result, "bin")) {
+ if (FileUtil.getExtension(result) != "bin") {
MessageDialogFragment.newInstance(
R.string.reading_keys_failure,
R.string.install_amiibo_keys_failure_extension_description
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt
index 9f3bbe56f..142af5f26 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt
@@ -7,7 +7,6 @@ import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.provider.DocumentsContract
-import android.provider.OpenableColumns
import androidx.documentfile.provider.DocumentFile
import java.io.BufferedInputStream
import java.io.File
@@ -185,19 +184,18 @@ object FileUtil {
/**
* Get file display name from given path
- * @param path content uri path
+ * @param uri content uri
* @return String display name
*/
- fun getFilename(context: Context, path: String): String {
- val resolver = context.contentResolver
+ fun getFilename(uri: Uri): String {
+ val resolver = YuzuApplication.appContext.contentResolver
val columns = arrayOf(
DocumentsContract.Document.COLUMN_DISPLAY_NAME
)
var filename = ""
var c: Cursor? = null
try {
- val mUri = Uri.parse(path)
- c = resolver.query(mUri, columns, null, null, null)
+ c = resolver.query(uri, columns, null, null, null)
c!!.moveToNext()
filename = c.getString(0)
} catch (e: Exception) {
@@ -326,25 +324,9 @@ object FileUtil {
}
}
- fun hasExtension(path: String, extension: String): Boolean =
- path.substring(path.lastIndexOf(".") + 1).contains(extension)
-
- fun hasExtension(uri: Uri, extension: String): Boolean {
- val fileName: String?
- val cursor = YuzuApplication.appContext.contentResolver.query(uri, null, null, null, null)
- val nameIndex = cursor?.getColumnIndex(OpenableColumns.DISPLAY_NAME)
- cursor?.moveToFirst()
-
- if (nameIndex == null) {
- return false
- }
-
- fileName = cursor.getString(nameIndex)
- cursor.close()
-
- if (fileName == null) {
- return false
- }
- return fileName.substring(fileName.lastIndexOf(".") + 1).contains(extension)
+ fun getExtension(uri: Uri): String {
+ val fileName = getFilename(uri)
+ return fileName.substring(fileName.lastIndexOf(".") + 1)
+ .lowercase()
}
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
index ee9f3e570..f8e7eeca7 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
@@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.utils
import android.content.SharedPreferences
import android.net.Uri
import androidx.preference.PreferenceManager
-import java.util.*
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.yuzu.yuzu_emu.NativeLibrary
@@ -33,15 +32,9 @@ object GameHelper {
val children = FileUtil.listFiles(context, gamesUri)
for (file in children) {
if (!file.isDirectory) {
- val filename = file.uri.toString()
- val extensionStart = filename.lastIndexOf('.')
- if (extensionStart > 0) {
- val fileExtension = filename.substring(extensionStart)
-
- // Check that the file has an extension we care about before trying to read out of it.
- if (Game.extensions.contains(fileExtension.lowercase(Locale.getDefault()))) {
- games.add(getGame(filename))
- }
+ // Check that the file has an extension we care about before trying to read out of it.
+ if (Game.extensions.contains(FileUtil.getExtension(file.uri))) {
+ games.add(getGame(file.uri))
}
}
}
@@ -59,21 +52,19 @@ object GameHelper {
return games.toList()
}
- private fun getGame(filePath: String): Game {
+ private fun getGame(uri: Uri): Game {
+ val filePath = uri.toString()
var name = NativeLibrary.getTitle(filePath)
// If the game's title field is empty, use the filename.
if (name.isEmpty()) {
- name = filePath.substring(filePath.lastIndexOf("/") + 1)
+ name = FileUtil.getFilename(uri)
}
var gameId = NativeLibrary.getGameId(filePath)
// If the game's ID field is empty, use the filename without extension.
if (gameId.isEmpty()) {
- gameId = filePath.substring(
- filePath.lastIndexOf("/") + 1,
- filePath.lastIndexOf(".")
- )
+ gameId = name.substring(0, name.lastIndexOf("."))
}
val newGame = Game(
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index d576aac50..8bc6a4a04 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -60,6 +60,9 @@
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
+#define jconst [[maybe_unused]] const auto
+#define jauto [[maybe_unused]] auto
+
namespace {
class EmulationSession final {
@@ -99,8 +102,8 @@ public:
}
int InstallFileToNand(std::string filename) {
- const auto copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
- std::size_t block_size) {
+ jconst copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
+ std::size_t block_size) {
if (src == nullptr || dest == nullptr) {
return false;
}
@@ -109,10 +112,10 @@ public:
}
using namespace Common::Literals;
- std::vector<u8> buffer(1_MiB);
+ [[maybe_unused]] std::vector<u8> buffer(1_MiB);
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
- const auto read = src->Read(buffer.data(), buffer.size(), i);
+ jconst read = src->Read(buffer.data(), buffer.size(), i);
dest->Write(buffer.data(), read, i);
}
return true;
@@ -129,14 +132,14 @@ public:
m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
m_system.GetFileSystemController().CreateFactories(*m_vfs);
- std::shared_ptr<FileSys::NSP> nsp;
+ [[maybe_unused]] std::shared_ptr<FileSys::NSP> nsp;
if (filename.ends_with("nsp")) {
nsp = std::make_shared<FileSys::NSP>(m_vfs->OpenFile(filename, FileSys::Mode::Read));
if (nsp->IsExtractedType()) {
return InstallError;
}
} else if (filename.ends_with("xci")) {
- const auto xci =
+ jconst xci =
std::make_shared<FileSys::XCI>(m_vfs->OpenFile(filename, FileSys::Mode::Read));
nsp = xci->GetSecurePartitionNSP();
} else {
@@ -151,7 +154,7 @@ public:
return InstallError;
}
- const auto res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry(
+ jconst res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry(
*nsp, true, copy_func);
switch (res) {
@@ -234,7 +237,7 @@ public:
m_system.SetFilesystem(m_vfs);
// Initialize system.
- auto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();
+ jauto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();
m_software_keyboard = android_keyboard.get();
m_system.SetShuttingDown(false);
m_system.ApplySettings();
@@ -332,7 +335,7 @@ public:
while (true) {
{
- std::unique_lock lock(m_mutex);
+ [[maybe_unused]] std::unique_lock lock(m_mutex);
if (m_cv.wait_for(lock, std::chrono::milliseconds(800),
[&]() { return !m_is_running; })) {
// Emulation halted.
@@ -364,7 +367,7 @@ public:
}
bool IsHandheldOnly() {
- const auto npad_style_set = m_system.HIDCore().GetSupportedStyleTag();
+ jconst npad_style_set = m_system.HIDCore().GetSupportedStyleTag();
if (npad_style_set.fullkey == 1) {
return false;
@@ -377,17 +380,17 @@ public:
return !Settings::values.use_docked_mode.GetValue();
}
- void SetDeviceType(int index, int type) {
- auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
+ void SetDeviceType([[maybe_unused]] int index, int type) {
+ jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type));
}
- void OnGamepadConnectEvent(int index) {
- auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
+ void OnGamepadConnectEvent([[maybe_unused]] int index) {
+ jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
// Ensure that player1 is configured correctly and handheld disconnected
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) {
- auto handheld =
+ jauto handheld =
m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) {
@@ -399,7 +402,8 @@ public:
// Ensure that handheld is configured correctly and player 1 disconnected
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) {
- auto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
+ jauto player1 =
+ m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) {
player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
@@ -413,8 +417,8 @@ public:
}
}
- void OnGamepadDisconnectEvent(int index) {
- auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
+ void OnGamepadDisconnectEvent([[maybe_unused]] int index) {
+ jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
controller->Disconnect();
}
@@ -430,7 +434,7 @@ private:
};
RomMetadata GetRomMetadata(const std::string& path) {
- if (auto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) {
+ if (jauto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) {
return search->second;
}
@@ -438,14 +442,14 @@ private:
}
RomMetadata CacheRomMetadata(const std::string& path) {
- const auto file = Core::GetGameFileFromPath(m_vfs, path);
- auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
+ jconst file = Core::GetGameFileFromPath(m_vfs, path);
+ jauto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
RomMetadata entry;
loader->ReadTitle(entry.title);
loader->ReadIcon(entry.icon);
if (loader->GetFileType() == Loader::FileType::NRO) {
- auto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get());
+ jauto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get());
entry.isHomebrew = loader_nro->IsHomebrew();
} else {
entry.isHomebrew = false;
@@ -516,7 +520,7 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
- const auto result = EmulationSession::GetInstance().InitializeEmulation(filepath);
+ jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath);
if (result != Core::SystemResultStatus::Success) {
return result;
}
@@ -528,24 +532,25 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
extern "C" {
-void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jclass clazz, jobject surf) {
+void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jobject instance,
+ [[maybe_unused]] jobject surf) {
EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf));
EmulationSession::GetInstance().SurfaceChanged();
}
-void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jclass clazz) {
+void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jobject instance) {
ANativeWindow_release(EmulationSession::GetInstance().NativeWindow());
EmulationSession::GetInstance().SetNativeWindow(nullptr);
EmulationSession::GetInstance().SurfaceChanged();
}
-void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jclass clazz,
- jstring j_directory) {
+void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jobject instance,
+ [[maybe_unused]] jstring j_directory) {
Common::FS::SetAppDirectory(GetJString(env, j_directory));
}
-int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jclass clazz,
- jstring j_file) {
+int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject instance,
+ [[maybe_unused]] jstring j_file) {
return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file));
}
@@ -570,7 +575,7 @@ void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(JNIEnv* e
}
jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDriverLoading(
- JNIEnv* env, [[maybe_unused]] jobject instance) {
+ JNIEnv* env, jobject instance) {
#ifdef ARCHITECTURE_arm64
// If the KGSL device exists custom drivers can be loaded using adrenotools
return SupportsCustomDriver();
@@ -648,8 +653,8 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent(JNIEnv*
return static_cast<jboolean>(true);
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent(JNIEnv* env, jclass clazz,
- [[maybe_unused]] jint j_device,
- jint j_button, jint action) {
+ jint j_device, jint j_button,
+ jint action) {
if (EmulationSession::GetInstance().IsRunning()) {
// Ensure gamepad is connected
EmulationSession::GetInstance().OnGamepadConnectEvent(j_device);
@@ -718,8 +723,8 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass c
}
jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon(JNIEnv* env, jclass clazz,
- [[maybe_unused]] jstring j_filename) {
- auto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename));
+ jstring j_filename) {
+ jauto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename));
jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size()));
env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon),
reinterpret_cast<jbyte*>(icon_data.data()));
@@ -727,8 +732,8 @@ jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon(JNIEnv* env, jclass cla
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle(JNIEnv* env, jclass clazz,
- [[maybe_unused]] jstring j_filename) {
- auto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename));
+ jstring j_filename) {
+ jauto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename));
return env->NewStringUTF(title.c_str());
}
@@ -743,22 +748,21 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId(JNIEnv* env, jclass claz
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions(JNIEnv* env, jclass clazz,
- [[maybe_unused]] jstring j_filename) {
+ jstring j_filename) {
return env->NewStringUTF("");
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany(JNIEnv* env, jclass clazz,
- [[maybe_unused]] jstring j_filename) {
+ jstring j_filename) {
return env->NewStringUTF("");
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew(JNIEnv* env, jclass clazz,
- [[maybe_unused]] jstring j_filename) {
+ jstring j_filename) {
return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename));
}
-void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation
- [[maybe_unused]] (JNIEnv* env, jclass clazz) {
+void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation(JNIEnv* env, jclass clazz) {
// Create the default config.ini.
Config{};
// Initialize the emulated system.
@@ -770,8 +774,7 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass cl
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z(
- JNIEnv* env, jclass clazz, [[maybe_unused]] jstring j_file,
- [[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {}
+ JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate) {}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings(JNIEnv* env, jclass clazz) {
Config{};
@@ -816,7 +819,7 @@ jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jcl
jdoubleArray j_stats = env->NewDoubleArray(4);
if (EmulationSession::GetInstance().IsRunning()) {
- const auto results = EmulationSession::GetInstance().PerfStats();
+ jconst results = EmulationSession::GetInstance().PerfStats();
// Converting the structure into an array makes it easier to pass it to the frontend
double stats[4] = {results.system_fps, results.average_game_fps, results.frametime,
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index c937495f9..1ebc32c1e 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -1250,6 +1250,11 @@ Common::Input::DriverResult EmulatedController::SetPollingMode(
const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode);
const auto mapped_nfc_result = right_output_device->SetPollingMode(polling_mode);
+ // Restore previous state
+ if (mapped_nfc_result != Common::Input::DriverResult::Success) {
+ right_output_device->SetPollingMode(Common::Input::PollingMode::Active);
+ }
+
if (virtual_nfc_result == Common::Input::DriverResult::Success) {
return virtual_nfc_result;
}
@@ -1329,16 +1334,22 @@ bool EmulatedController::StartNfcPolling() {
auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
auto& nfc_virtual_output_device = output_devices[3];
- return nfc_output_device->StartNfcPolling() == Common::Input::NfcState::Success ||
- nfc_virtual_output_device->StartNfcPolling() == Common::Input::NfcState::Success;
+ const auto device_result = nfc_output_device->StartNfcPolling();
+ const auto virtual_device_result = nfc_virtual_output_device->StartNfcPolling();
+
+ return device_result == Common::Input::NfcState::Success ||
+ virtual_device_result == Common::Input::NfcState::Success;
}
bool EmulatedController::StopNfcPolling() {
auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
auto& nfc_virtual_output_device = output_devices[3];
- return nfc_output_device->StopNfcPolling() == Common::Input::NfcState::Success ||
- nfc_virtual_output_device->StopNfcPolling() == Common::Input::NfcState::Success;
+ const auto device_result = nfc_output_device->StopNfcPolling();
+ const auto virtual_device_result = nfc_virtual_output_device->StopNfcPolling();
+
+ return device_result == Common::Input::NfcState::Success ||
+ virtual_device_result == Common::Input::NfcState::Success;
}
bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) {
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index 9a0439bb5..3cc639ba7 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -150,6 +150,8 @@ public:
if (sdl_controller) {
const auto type = SDL_GameControllerGetType(sdl_controller.get());
return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) ||
+ (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) ||
+ (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) ||
(type == SDL_CONTROLLER_TYPE_PS5);
}
return false;
@@ -228,9 +230,8 @@ public:
return false;
}
- Common::Input::BatteryLevel GetBatteryLevel() {
- const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get());
- switch (level) {
+ Common::Input::BatteryLevel GetBatteryLevel(SDL_JoystickPowerLevel battery_level) {
+ switch (battery_level) {
case SDL_JOYSTICK_POWER_EMPTY:
return Common::Input::BatteryLevel::Empty;
case SDL_JOYSTICK_POWER_LOW:
@@ -378,7 +379,6 @@ void SDLDriver::InitJoystick(int joystick_index) {
if (joystick_map.find(guid) == joystick_map.end()) {
auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
PreSetController(joystick->GetPadIdentifier());
- SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
joystick->EnableMotion();
joystick_map[guid].emplace_back(std::move(joystick));
return;
@@ -398,7 +398,6 @@ void SDLDriver::InitJoystick(int joystick_index) {
const int port = static_cast<int>(joystick_guid_list.size());
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
PreSetController(joystick->GetPadIdentifier());
- SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
joystick->EnableMotion();
joystick_guid_list.emplace_back(std::move(joystick));
}
@@ -438,8 +437,6 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
const PadIdentifier identifier = joystick->GetPadIdentifier();
SetButton(identifier, event.jbutton.button, true);
- // Battery doesn't trigger an event so just update every button press
- SetBattery(identifier, joystick->GetBatteryLevel());
}
break;
}
@@ -466,6 +463,13 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
}
break;
}
+ case SDL_JOYBATTERYUPDATED: {
+ if (auto joystick = GetSDLJoystickBySDLID(event.jbattery.which)) {
+ const PadIdentifier identifier = joystick->GetPadIdentifier();
+ SetBattery(identifier, joystick->GetBatteryLevel(event.jbattery.level));
+ }
+ break;
+ }
case SDL_JOYDEVICEREMOVED:
LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
@@ -501,6 +505,9 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0");
} else {
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
+ SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED, "0");
+ SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "0");
+ SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, "1");
}
// Disable hidapi drivers for pro controllers when the custom joycon driver is enabled
@@ -508,8 +515,11 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0");
} else {
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1");
+ SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0");
}
+ SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1");
+
// Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native
// driver on Linux.
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0");
@@ -789,7 +799,9 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p
// This list also excludes Screenshot since there's not really a mapping for that
ButtonBindings switch_to_sdl_button;
- if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) {
+ if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO ||
+ SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT ||
+ SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) {
switch_to_sdl_button = GetNintendoButtonBinding(joystick);
} else {
switch_to_sdl_button = GetDefaultButtonBinding();
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp
index 2c8c66951..ec984a647 100644
--- a/src/input_common/helpers/joycon_driver.cpp
+++ b/src/input_common/helpers/joycon_driver.cpp
@@ -72,6 +72,7 @@ DriverResult JoyconDriver::InitializeDevice() {
nfc_enabled = false;
passive_enabled = false;
irs_enabled = false;
+ input_only_device = false;
gyro_sensitivity = Joycon::GyroSensitivity::DPS2000;
gyro_performance = Joycon::GyroPerformance::HZ833;
accelerometer_sensitivity = Joycon::AccelerometerSensitivity::G8;
@@ -86,16 +87,23 @@ DriverResult JoyconDriver::InitializeDevice() {
rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle);
// Get fixed joycon info
- generic_protocol->GetVersionNumber(version);
- generic_protocol->SetLowPowerMode(false);
- generic_protocol->GetColor(color);
- if (handle_device_type == ControllerType::Pro) {
- // Some 3rd party controllers aren't pro controllers
- generic_protocol->GetControllerType(device_type);
- } else {
- device_type = handle_device_type;
+ if (generic_protocol->GetVersionNumber(version) != DriverResult::Success) {
+ // If this command fails the device doesn't accept configuration commands
+ input_only_device = true;
}
- generic_protocol->GetSerialNumber(serial_number);
+
+ if (!input_only_device) {
+ generic_protocol->SetLowPowerMode(false);
+ generic_protocol->GetColor(color);
+ if (handle_device_type == ControllerType::Pro) {
+ // Some 3rd party controllers aren't pro controllers
+ generic_protocol->GetControllerType(device_type);
+ } else {
+ device_type = handle_device_type;
+ }
+ generic_protocol->GetSerialNumber(serial_number);
+ }
+
supported_features = GetSupportedFeatures();
// Get Calibration data
@@ -261,6 +269,10 @@ DriverResult JoyconDriver::SetPollingMode() {
generic_protocol->EnableImu(false);
}
+ if (input_only_device) {
+ return DriverResult::NotSupported;
+ }
+
if (irs_protocol->IsEnabled()) {
irs_protocol->DisableIrs();
}
@@ -282,6 +294,7 @@ DriverResult JoyconDriver::SetPollingMode() {
}
irs_protocol->DisableIrs();
LOG_ERROR(Input, "Error enabling IRS");
+ return result;
}
if (nfc_enabled && supported_features.nfc) {
@@ -291,6 +304,7 @@ DriverResult JoyconDriver::SetPollingMode() {
}
nfc_protocol->DisableNfc();
LOG_ERROR(Input, "Error enabling NFC");
+ return result;
}
if (hidbus_enabled && supported_features.hidbus) {
@@ -305,6 +319,7 @@ DriverResult JoyconDriver::SetPollingMode() {
ring_connected = false;
ring_protocol->DisableRingCon();
LOG_ERROR(Input, "Error enabling Ringcon");
+ return result;
}
if (passive_enabled && supported_features.passive) {
@@ -333,6 +348,10 @@ JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() {
.vibration = true,
};
+ if (input_only_device) {
+ return features;
+ }
+
if (device_type == ControllerType::Right) {
features.nfc = true;
features.irs = true;
@@ -517,6 +536,11 @@ DriverResult JoyconDriver::StopNfcPolling() {
const auto result = nfc_protocol->StopNFCPollingMode();
disable_input_thread = false;
+ if (amiibo_detected) {
+ amiibo_detected = false;
+ joycon_poller->UpdateAmiibo({});
+ }
+
return result;
}
diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h
index bc7025a21..45b32d2f8 100644
--- a/src/input_common/helpers/joycon_driver.h
+++ b/src/input_common/helpers/joycon_driver.h
@@ -120,6 +120,7 @@ private:
// Hardware configuration
u8 leds{};
ReportMode mode{};
+ bool input_only_device{};
bool passive_enabled{}; // Low power mode, Ideal for multiple controllers at the same time
bool hidbus_enabled{}; // External device support
bool irs_enabled{}; // Infrared camera input
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
index 51669261a..88f4cec1c 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
@@ -73,7 +73,7 @@ DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) {
DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc,
SubCommandResponse& output) {
constexpr int timeout_mili = 66;
- constexpr int MaxTries = 15;
+ constexpr int MaxTries = 3;
int tries = 0;
do {
@@ -113,9 +113,7 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const
return result;
}
- result = GetSubCommandResponse(sc, output);
-
- return DriverResult::Success;
+ return GetSubCommandResponse(sc, output);
}
DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) {
@@ -158,7 +156,7 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) {
constexpr std::size_t HeaderSize = 5;
- constexpr std::size_t MaxTries = 10;
+ constexpr std::size_t MaxTries = 5;
std::size_t tries = 0;
SubCommandResponse response{};
std::array<u8, sizeof(ReadSpiPacket)> buffer{};